package org.jflame.commons.excel;

import org.jflame.commons.util.StringHelper;

import java.util.List;

import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.FontUnderline;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * 一个以类css样式表示excel cell style的类. 支持的样式:
 * <ol>
 * <li>width: 列宽, 设置样式</li>
 * <li>align: 水平对齐, 取值参考{@link org.apache.poi.ss.usermodel.HorizontalAlignment},常用如:center,left,right,justify.</li>
 * <li>fontName: 字体名, 名称带空格时用单引号包围</li>
 * <li>fontStyle: 字体样式, 包括:字体大小、加粗(bold)、下划线(underline)、斜体(italic)、中划线(strikeout). 多属性以空格分开,如:16号字体/红色/加粗 '16 red
 * bold'</li>
 * <li>bgColor: 背景色, 颜色可使用内置颜色名称{@link IndexedColors}或6位16进制RGB表示法. ,示例: bgColor:#000000</li>
 * <li>border: 边框样式, 包括边框线样式{@link org.apache.poi.ss.usermodel.BorderStyle}和颜色. 示例: border:dotted 或 border:'dotted
 * #cccccc'</li>
 * </ol>
 * 
 * @author charles.zhang
 * @see ExcelColumn#style()
 * @see org.apache.poi.ss.usermodel.IndexedColors
 * @see org.apache.poi.ss.usermodel.HorizontalAlignment
 * @see org.apache.poi.ss.usermodel.BorderStyle
 */
public class CellCssStyle {

    /**
     * 列宽 (注:对应样式表示字符个数)
     */
    private Integer width;
    /**
     * 字体名
     */
    private String fontName;
    /**
     * 字体样式属性, 包括:字体大小、加粗(bold)、下划线(underline)、斜体(italic)、中划线(strikeout). 多属性以空格分开
     */
    private String fontStyle;
    /**
     * 背景色. 预置颜色或16进制颜色表示(black or #000000)
     * 
     * @see org.apache.poi.ss.usermodel.IndexedColors
     */
    private String bgColor;
    /**
     * 水平对齐方式,取值:center,left,right,justify
     * 
     * @see org.apache.poi.ss.usermodel.HorizontalAlignment
     */
    private String align;
    /**
     * 边框样式,示例:border:'dotted black' 或 border:'dotted #000000'
     * 
     * @see org.apache.poi.ss.usermodel.BorderStyle
     * @see org.apache.poi.ss.usermodel.IndexedColors
     */
    private String border;

    /**
     * 解析样式字符串为CellCssStyle. 样式示例:
     * <p>
     * 1. fontName:Arial;fontStyle:'16 strikeout';align:center;bgColor:black;border:'dotted black'<br>
     * 2. width:20;fontName:'Arial Black';fontStyle:'red bold';border:'dotted #000000'
     * 
     * @param css 样式
     * @return
     * @see ExcelColumn#style()
     */
    public static CellCssStyle parse(String css) {
        StringHelper.requireNonEmpty(css, "css must not be null");
        List<String> tokens = StringHelper.tokenizeToStrings(css, ";", true, true);
        CellCssStyle cssStyle = new CellCssStyle();
        String styleName,styleVal;
        for (String cssToken : tokens) {
            String[] cssKv = StringHelper.split(cssToken, ':');
            if (cssKv.length < 2) {
                continue;
            }
            styleName = cssKv[0].trim();
            styleVal = cssKv[1].trim();
            if (styleVal.charAt(0) == '\'') {
                styleVal = StringHelper.strip(styleVal, "'");
            }
            if ("width".equals(styleName)) {
                try {
                    cssStyle.setCharWidth(Integer.parseInt(styleVal));
                } catch (NumberFormatException e) {
                }
            } else {
                try {
                    FieldUtils.writeField(cssStyle, styleName, styleVal, true);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return cssStyle;
    }

    /**
     * 解析为CellStyle
     * 
     * @param workbook
     * @return
     */
    public CellStyle toCellStyle(Workbook workbook) {
        CellStyle cellStyle = workbook.createCellStyle();
        boolean hasAnyStyle = false;
        // 设置居中对齐
        if (align != null) {
            try {
                cellStyle.setAlignment(HorizontalAlignment.valueOf(align.toUpperCase()));
                hasAnyStyle = true;
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
        }
        // 设置背影色
        if (StringHelper.isNotEmpty(bgColor)) {
            cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            if (bgColor.charAt(0) == '#') {
                if (cellStyle instanceof XSSFCellStyle) {
                    ((XSSFCellStyle) cellStyle).setFillForegroundColor(toXSSFColor(bgColor, workbook));
                } else {
                    cellStyle.setFillForegroundColor(toColorIndex(bgColor, workbook));
                }
                hasAnyStyle = true;
            } else {
                try {
                    cellStyle.setFillForegroundColor(IndexedColors.valueOf(bgColor.toUpperCase())
                            .getIndex());
                    hasAnyStyle = true;
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                }
            }
        }
        // 设置边框样式
        if (border != null) {
            String[] borderArr = StringHelper.split(border, " ");
            for (String style : borderArr) {
                short bc;
                if (style.charAt(0) == '#') {
                    bc = toColorIndex(style, workbook);
                    cellStyle.setTopBorderColor(bc);
                    cellStyle.setRightBorderColor(bc);
                    cellStyle.setBottomBorderColor(bc);
                    cellStyle.setLeftBorderColor(bc);
                    hasAnyStyle = true;
                    continue;
                }

                try {
                    bc = IndexedColors.valueOf(style.toUpperCase())
                            .getIndex();
                    cellStyle.setTopBorderColor(bc);
                    cellStyle.setRightBorderColor(bc);
                    cellStyle.setBottomBorderColor(bc);
                    cellStyle.setLeftBorderColor(bc);
                    hasAnyStyle = true;
                    continue;
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                }
                BorderStyle bs;
                try {
                    bs = BorderStyle.valueOf(style.toUpperCase());
                    cellStyle.setBorderTop(bs);
                    cellStyle.setBorderRight(bs);
                    cellStyle.setBorderBottom(bs);
                    cellStyle.setBorderLeft(bs);
                    hasAnyStyle = true;
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                }

            }
        }

        if (StringHelper.isNotEmpty(fontName) || StringHelper.isNotEmpty(fontStyle)) {
            Font font = workbook.createFont();
            if (StringHelper.isNotEmpty(fontName)) {
                font.setFontName(fontName);
            }
            if (StringHelper.isNotEmpty(fontStyle)) {
                String[] fsArr = StringHelper.split(fontStyle, " ");
                for (String fs : fsArr) {
                    // bold ,Underline,Italic,strikeout
                    if ("bold".equals(fs)) {
                        font.setBold(true);
                    } else if ("underline".equals(fs)) {
                        font.setUnderline(FontUnderline.SINGLE.getByteValue());
                    } else if ("italic".equals(fs)) {
                        font.setItalic(true);
                    } else if ("strikeout".equals(fs)) {
                        font.setStrikeout(true);
                    } else {
                        if (NumberUtils.isDigits(fs)) {
                            font.setFontHeightInPoints(NumberUtils.toShort(fs));
                            continue;
                        }
                        try {
                            font.setColor(IndexedColors.valueOf(fs.toUpperCase())
                                    .getIndex());
                            continue;
                        } catch (IllegalArgumentException e) {
                        }
                        if (fs.charAt(0) == '#') {
                            font.setColor(toColorIndex(fs, workbook));
                        }
                    }
                }
            }
            hasAnyStyle = true;
            cellStyle.setFont(font);
        }

        return hasAnyStyle ? cellStyle : null;
    }

    short toColorIndex(String hexColor, Workbook workbook) {
        if (workbook instanceof HSSFWorkbook) {
            HSSFPalette palette = ((HSSFWorkbook) workbook).getCustomPalette();
            String r = hexColor.substring(1, 3);
            String g = hexColor.substring(3, 5);
            String b = hexColor.substring(5, 7);
            int r2 = Integer.parseInt(r, 16);
            int g2 = Integer.parseInt(g, 16);
            int b2 = Integer.parseInt(b, 16);
            HSSFColor hssfColor = palette.findSimilarColor(r2, g2, b2);
            return hssfColor.getIndex();
        } else if (workbook instanceof XSSFWorkbook) {
            return toColorIndex(hexColor, (XSSFWorkbook) workbook);
        } else if (workbook instanceof SXSSFWorkbook) {
            return toColorIndex(hexColor, ((SXSSFWorkbook) workbook).getXSSFWorkbook());
        }
        throw new IllegalArgumentException(workbook.getClass()
                .getName() + " is not supported");

    }

    XSSFColor toXSSFColor(String hexColor, Workbook workbook) {
        XSSFColor xssfColor;
        if (workbook instanceof XSSFWorkbook) {
            xssfColor = ((XSSFWorkbook) workbook).getCreationHelper()
                    .createExtendedColor();
        } else if (workbook instanceof SXSSFWorkbook) {
            xssfColor = ((SXSSFWorkbook) workbook).getXSSFWorkbook()
                    .getCreationHelper()
                    .createExtendedColor();
        } else {
            throw new IllegalArgumentException(workbook.getClass()
                    .getName() + " is not supported");
        }
        xssfColor.setARGBHex(hexColor.substring(1));
        return xssfColor;
    }

    short toColorIndex(String hexColor, XSSFWorkbook workbook) {
        XSSFColor xssfColor = workbook.getCreationHelper()
                .createExtendedColor();
        xssfColor.setARGBHex(hexColor.substring(1));
        return xssfColor.getIndex();
    }

    public Integer getWidth() {
        return width;
    }

    public void setWidth(Integer width) {
        this.width = width;
    }

    public void setCharWidth(Integer charCount) {
        this.width = charCount * 256;
    }

    public String getFontName() {
        return fontName;
    }

    public void setFontName(String fontName) {
        this.fontName = fontName;
    }

    public String getFontStyle() {
        return fontStyle;
    }

    public void setFontStyle(String fontStyle) {
        this.fontStyle = fontStyle;
    }

    public String getBgColor() {
        return bgColor;
    }

    public void setBgColor(String bgColor) {
        this.bgColor = bgColor;
    }

    public String getAlign() {
        return align;
    }

    public void setAlign(String align) {
        this.align = align;
    }

    public String getBorder() {
        return border;
    }

    public void setBorder(String border) {
        this.border = border;
    }

    /* public static int getIntFromColor(int Red, int Green, int Blue) {
        Red = (Red << 16) & 0x00FF0000;
        Green = (Green << 8) & 0x0000FF00;
        Blue = Blue & 0x000000FF;
        return 0xFF000000 | Red | Green | Blue;
    }*/
}
